package com.seventh7.mybatis.intention; import com.google.common.base.Function; import com.google.common.collect.Collections2; import com.google.common.collect.Lists; import com.google.common.collect.Maps; import com.intellij.codeInsight.hint.HintManager; import com.intellij.openapi.editor.Editor; import com.intellij.openapi.module.Module; import com.intellij.openapi.module.ModuleUtil; import com.intellij.openapi.project.Project; import com.intellij.openapi.util.io.FileUtil; import com.intellij.openapi.vfs.VirtualFile; import com.intellij.psi.PsiClass; import com.intellij.psi.PsiDirectory; import com.intellij.psi.PsiElement; import com.intellij.psi.PsiFile; import com.intellij.psi.PsiManager; import com.intellij.psi.util.PsiTreeUtil; import com.intellij.util.IncorrectOperationException; import com.seventh7.mybatis.service.EditorService; import com.seventh7.mybatis.template.MybatisFileTemplateDescriptorFactory; import com.seventh7.mybatis.ui.ClickableListener; import com.seventh7.mybatis.ui.ListSelectionListener; import com.seventh7.mybatis.ui.UiComponentFacade; import com.seventh7.mybatis.util.CollectionUtils; import com.seventh7.mybatis.util.MapperUtils; import org.jetbrains.annotations.NotNull; import java.io.File; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; import java.util.List; import java.util.Map; import java.util.Properties; /** * @author yanglin */ public class GenerateMapperIntention extends GenericIntention { public GenerateMapperIntention() { super(GenerateMapperChooser.INSTANCE); } @NotNull @Override public String getText() { return "[Mybatis] Generate mapper of xml"; } @Override public boolean startInWriteAction() { return false; } @Override public void invoke(@NotNull final Project project, final Editor editor, PsiFile file) throws IncorrectOperationException { PsiElement element = file.findElementAt(editor.getCaretModel().getOffset()); PsiClass clazz = PsiTreeUtil.getParentOfType(element, PsiClass.class); Collection<PsiDirectory> directories = MapperUtils.findMapperDirectories(project); if (CollectionUtils.isEmpty(directories)) { handleChooseNewFolder(project, editor, clazz); } else { handleMutilDirectories(project, editor, clazz, directories); } } private void handleMutilDirectories(Project project, final Editor editor, final PsiClass clazz, Collection<PsiDirectory> directories) { final Map<String, PsiDirectory> pathMap = getPathMap(directories); final ArrayList<String> keys = Lists.newArrayList(pathMap.keySet()); ListSelectionListener popupListener = new ListSelectionListener() { @Override public void selected(int index) { processGenerate(editor, clazz, pathMap.get(keys.get(index))); } @Override public boolean isWriteAction() { return true; } }; UiComponentFacade uiComponentFacade = UiComponentFacade.getInstance(project); uiComponentFacade.showListPopupWithSingleClickable("Choose folder", popupListener, "Choose another", getChooseFolderListener(editor, clazz), getPathTextForShown(project, keys, pathMap)); } private ClickableListener getChooseFolderListener(final Editor editor, final PsiClass clazz) { final Project project = clazz.getProject(); return new ClickableListener() { @Override public void clicked() { handleChooseNewFolder(project, editor, clazz); } @Override public boolean isWriteAction() { return false; } }; } private void handleChooseNewFolder(Project project, Editor editor, PsiClass clazz) { UiComponentFacade uiComponentFacade = UiComponentFacade.getInstance(project); VirtualFile baseDir = project.getBaseDir(); VirtualFile vf = uiComponentFacade.showSingleFolderSelectionDialog("Select target folder", baseDir, baseDir); if (null != vf) { processGenerate(editor, clazz, PsiManager.getInstance(project).findDirectory(vf)); } } private String[] getPathTextForShown(Project project, List<String> paths, final Map<String, PsiDirectory> pathMap) { Collections.sort(paths); final String projectBasePath = project.getBasePath(); Collection<String> result = Lists.newArrayList(Collections2.transform(paths, new Function<String, String>() { @Override public String apply(String input) { String relativePath = FileUtil.getRelativePath(projectBasePath, input, File.separatorChar); Module module = ModuleUtil.findModuleForPsiElement(pathMap.get(input)); return null == module ? relativePath : ("[" + module.getName() + "] " + relativePath); } })); return result.toArray(new String[result.size()]); } private Map<String, PsiDirectory> getPathMap(Collection<PsiDirectory> directories) { Map<String, PsiDirectory> result = Maps.newHashMap(); for (PsiDirectory directory : directories) { String presentableUrl = directory.getVirtualFile().getPresentableUrl(); if (presentableUrl != null) { result.put(presentableUrl, directory); } } return result; } private void processGenerate(Editor editor, PsiClass clazz, PsiDirectory directory) { if (null == directory) { return; } if (!directory.isWritable()) { HintManager.getInstance().showErrorHint(editor, "Target directory is not writable"); return; } try { Properties properties = new Properties(); properties.setProperty("NAMESPACE", clazz.getQualifiedName()); PsiElement psiFile = MapperUtils.createMapperFromFileTemplate(MybatisFileTemplateDescriptorFactory.MYBATIS_MAPPER_XML_TEMPLATE, clazz.getName(), directory, properties); EditorService.getInstance(clazz.getProject()).scrollTo(psiFile, 0); } catch (Exception e) { HintManager.getInstance().showErrorHint(editor, "Failed: " + e.getCause()); } } }